#!/bin/bash

# DLSystem Protocol Build Script

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 项目配置
load_project_config() {
    if [ -f "config/build.conf" ]; then
        # 从build.conf的[project]段读取项目信息
        local in_project_section=false
        while IFS= read -r line; do
            # 检查是否进入project段
            if [[ "$line" =~ ^\[project\]$ ]]; then
                in_project_section=true
                continue
            elif [[ "$line" =~ ^\[.*\]$ ]]; then
                in_project_section=false
                continue
            fi
            
            # 如果在project段内，解析配置
            if [ "$in_project_section" = true ] && [[ "$line" =~ ^([^=]+)=(.*)$ ]]; then
                local key="${BASH_REMATCH[1]// /}"
                local value="${BASH_REMATCH[2]}"
                
                # 去除值两端的引号和空格
                value=$(echo "$value" | sed 's/^"*//;s/"*$//')
                
                case "$key" in
                    "app_name")
                        PROJECT_NAME="$value"
                        ;;
                    "version")
                        PROJECT_VERSION="$value"
                        ;;
                esac
            fi
        done < "config/build.conf"
    fi
    
    # 设置默认值
    PROJECT_NAME=${PROJECT_NAME:-"DLSystem Protocol"}
    PROJECT_VERSION=${PROJECT_VERSION:-"1.0.0"}
}

load_project_config
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
THIRD_PARTY_DIR="$SCRIPT_DIR/third"

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

log_debug() {
    echo -e "${BLUE}[DEBUG]${NC} $1"
}

# 检查命令是否存在
check_command() {
    if ! command -v "$1" &> /dev/null; then
        log_error "命令 '$1' 未找到，请先安装"
        exit 1
    fi
}

# 检查网络连接
check_network() {
    if ping -c 1 8.8.8.8 &> /dev/null; then
        return 0
    else
        return 1
    fi
}

# 显示项目信息
show_project_info() {
    echo
    echo -e "${BLUE}================================${NC}"
    echo -e "${BLUE}  $PROJECT_NAME v$PROJECT_VERSION${NC}"
    echo -e "${BLUE}================================${NC}"
    echo
}

# 克隆第三方依赖库
clone_third_party() {
    log_info "开始克隆第三方依赖库..."
    
    check_command "git"
    
    if ! check_network; then
        log_error "网络连接失败，无法克隆第三方库"
        exit 1
    fi
    
    if [ ! -f "$SCRIPT_DIR/scripts/download_third_party.sh" ]; then
        log_error "下载脚本不存在: $SCRIPT_DIR/scripts/download_third_party.sh"
        exit 1
    fi
    
    "$SCRIPT_DIR/scripts/download_third_party.sh"
    update_third_party_config
    
    log_info "第三方依赖库克隆完成"
}

# 更新第三方库配置文件
update_third_party_config() {
    log_debug "从配置文件生成第三方库Makefile配置..."
    
    if [ ! -d "config/third" ]; then
        log_error "第三方库配置目录不存在: config/third"
        exit 1
    fi
    
    cat > "$THIRD_PARTY_DIR/Makefile.inc" << EOF
# 第三方库配置文件
# 自动生成，请勿手动修改

EOF
    
    local includes=""
    local sources=""
    local libs=""
    local deps=""
    
    process_library_config() {
        local module_name="$1"
        local config_file="$2"
        
        local include_path=""
        local source_files=""
        local lib_list=""
        
        while IFS= read -r line; do
            if [[ "$line" =~ ^#.*$ ]] || [[ -z "$line" ]]; then
                continue
            fi
            
            if [[ "$line" =~ ^([^=]+)=(.*)$ ]]; then
                local key="${BASH_REMATCH[1]// /}"
                local value="${BASH_REMATCH[2]}"
                
                case "$key" in
                    "include_path")
                        include_path="$value"
                        ;;
                    "source_files")
                        source_files="$value"
                        ;;
                    "libs")
                        lib_list="$value"
                        ;;
                esac
            fi
        done < "$config_file"
        
        generate_library_config "$module_name" "$include_path" "$source_files" "$lib_list"
        collect_library_config "$module_name" "$include_path" "$source_files" "$lib_list"
    }
    
    generate_library_config() {
        local module_name="$1"
        local include_path="$2"
        local source_files="$3"
        local lib_list="$4"
        
        local upper_name=$(echo "$module_name" | tr '[:lower:]' '[:upper:]')
        cat >> "$THIRD_PARTY_DIR/Makefile.inc" << EOF
# ${module_name}库配置
${upper_name}_DIR = \$(THIRD_PARTY_DIR)/${module_name}
EOF
        
        if [ -n "$include_path" ] && [ "$include_path" != "." ]; then
            cat >> "$THIRD_PARTY_DIR/Makefile.inc" << EOF
${upper_name}_INCLUDE = -I\$(${upper_name}_DIR)/${include_path}
EOF
        else
            cat >> "$THIRD_PARTY_DIR/Makefile.inc" << EOF
${upper_name}_INCLUDE = -I\$(${upper_name}_DIR)
EOF
        fi
        
        if [ -n "$source_files" ]; then
            local source_list=""
            IFS=',' read -ra SOURCES <<< "$source_files"
            for source in "${SOURCES[@]}"; do
                source=$(echo "$source" | xargs)
                if [ -n "$include_path" ] && [ "$include_path" != "." ]; then
                    source_list+="\$(${upper_name}_DIR)/${include_path}/${source} "
                else
                    source_list+="\$(${upper_name}_DIR)/${source} "
                fi
            done
            cat >> "$THIRD_PARTY_DIR/Makefile.inc" << EOF
${upper_name}_SOURCES = ${source_list}
EOF
        fi
        
        if [ -n "$lib_list" ]; then
            local lib_list_formatted=""
            IFS=',' read -ra LIBS <<< "$lib_list"
            for lib in "${LIBS[@]}"; do
                lib=$(echo "$lib" | xargs)
                if [ -n "$lib" ]; then
                    lib_list_formatted+="-l${lib} "
                fi
            done
            cat >> "$THIRD_PARTY_DIR/Makefile.inc" << EOF
${upper_name}_LIBS = ${lib_list_formatted}
EOF
        fi
        
        cat >> "$THIRD_PARTY_DIR/Makefile.inc" << EOF

EOF
    }
    
    collect_library_config() {
        local module_name="$1"
        local include_path="$2"
        local source_files="$3"
        local lib_list="$4"
        
        local upper_name=$(echo "$module_name" | tr '[:lower:]' '[:upper:]')
        
        includes+="\$(${upper_name}_INCLUDE) "
        if [ -n "$source_files" ]; then
            sources+="\$(${upper_name}_SOURCES) "
            deps+="\$(${upper_name}_SOURCES) "
        fi
        if [ -n "$lib_list" ]; then
            libs+="\$(${upper_name}_LIBS) "
        fi
    }
    
    if [ -d "config/third" ]; then
        for config_file in config/third/*.conf; do
            if [ -f "$config_file" ]; then
                local module_name=$(basename "$config_file" .conf)
                log_debug "处理库配置: $module_name"
                process_library_config "$module_name" "$config_file"
            fi
        done
    else
        log_warn "第三方库配置目录不存在: config/third"
    fi
    
    cat >> "$THIRD_PARTY_DIR/Makefile.inc" << EOF
# 第三方库总配置
THIRD_PARTY_INCLUDES = ${includes}
THIRD_PARTY_SOURCES = ${sources}
THIRD_PARTY_LIBS = ${libs}
THIRD_PARTY_DEPS = ${deps}
EOF
    
    log_debug "第三方库Makefile配置生成完成"
}

# 检查第三方库
check_third_party() {
    log_info "检查第三方依赖库..."
    
    if [ ! -d "$THIRD_PARTY_DIR" ]; then
        log_error "第三方库目录不存在: $THIRD_PARTY_DIR"
        log_info "请先运行: $0 clone"
        exit 1
    fi
    
    local missing_libs=()
    
    if [ -d "config/third" ]; then
        for config_file in config/third/*.conf; do
            if [ -f "$config_file" ]; then
                local module_name=$(basename "$config_file" .conf)
                local lib_dir="$THIRD_PARTY_DIR/$module_name"
                
                if [ ! -d "$lib_dir" ]; then
                    missing_libs+=("$module_name")
                fi
            fi
        done
    fi
    
    if [ ${#missing_libs[@]} -gt 0 ]; then
        log_error "缺少以下第三方库: ${missing_libs[*]}"
        log_info "请运行: $0 clone"
        exit 1
    fi
    
    # 检查并构建MQTT库
    if [ -d "$THIRD_PARTY_DIR/mqtt" ] && [ ! -f "$THIRD_PARTY_DIR/mqtt/build/output/libpaho-mqtt3c.so" ]; then
        log_info "构建MQTT库..."
        if ! (cd "$THIRD_PARTY_DIR/mqtt" && make -j4 build > /dev/null 2>&1); then
            log_error "MQTT库构建失败"
            exit 1
        fi
    fi
    
    # 检查并构建cJSON库
    if [ -d "$THIRD_PARTY_DIR/cJSON" ] && [ ! -f "$THIRD_PARTY_DIR/cJSON/libcjson.a" ]; then
        log_info "构建cJSON库..."
        if ! (cd "$THIRD_PARTY_DIR/cJSON" && make libcjson.a > /dev/null 2>&1); then
            log_error "cJSON库构建失败"
            exit 1
        fi
    fi
    
    log_info "第三方依赖库检查完成"
}

# set命令 - 交互式配置
set_config() {
    log_info "开始配置..."
    
    show_project_info
    
    # 第一步：选择协议类型
    echo
    echo "请选择要编译的协议:"
    echo "1) 104协议 (IEC 60870-5-104)"
    echo "2) 退出"
    echo
    read -p "请输入选择 (1-2): " protocol_choice
    
    case $protocol_choice in
        1)
            PROTOCOL="104"
            ;;
        2)
            log_info "退出配置"
            exit 0
            ;;
        *)
            log_error "无效选择"
            exit 1
            ;;
    esac
    
    # 第二步：选择构建版本
    echo
    echo "请选择构建版本:"
    echo "1) Debug    - 调试版本，包含所有调试信息和日志"
    echo "2) Release  - 生产版本，优化性能，减少日志"
    echo
    read -p "请输入选择 (1-2): " version_choice
    
    case $version_choice in
        1)
            BUILD_VERSION="debug"
            ;;
        2)
            BUILD_VERSION="release"
            ;;
        *)
            log_warn "无效选择，使用默认版本: debug"
            BUILD_VERSION="debug"
            ;;
    esac
    
    # 保存配置到文件
    mkdir -p .build_config
    cat > .build_config/current.conf << EOF
PROTOCOL=$PROTOCOL
BUILD_VERSION=$BUILD_VERSION
EOF
    
    log_info "配置完成:"
    log_info "  协议类型: $PROTOCOL"
    log_info "  构建版本: $BUILD_VERSION"
    log_info "配置文件已保存到: .build_config/current.conf"
    echo
    
    log_info "请运行 ./build.sh build 开始构建"
}

# 选择构建版本（交互式）
select_build_version() {
    echo
    echo "请选择构建版本:"
    echo "1) Debug    - 调试版本，包含所有调试信息和日志"
    echo "2) Release  - 生产版本，优化性能，减少日志"
    echo
    read -p "请输入选择 (1-2): " version_choice
    
    case $version_choice in
        1)
            echo "debug"
            ;;
        2)
            echo "release"
            ;;
        *)
            log_warn "无效选择，使用默认版本: debug"
            echo "debug"
            ;;
    esac
}

# 构建所有模块
build_all() {
    local version="$1"
    
    # 如果没有提供版本参数，尝试从配置文件读取
    if [ -z "$version" ]; then
        if [ -f ".build_config/current.conf" ]; then
            log_info "从配置文件读取构建版本..."
            source .build_config/current.conf
            version="$BUILD_VERSION"
        else
            # 如果配置文件也不存在，则交互式选择
            version=$(select_build_version)
            echo
        fi
    fi
    
    BUILD_VERSION="$version"
    BUILD_TESTS="no"
    
    log_info "开始构建所有模块..."
    
    check_third_party
    
    show_project_info
    log_info "构建版本: $BUILD_VERSION"
    
    # 设置构建环境变量
    export BUILD_VERSION
    export BUILD_TESTS
    
    log_info "构建通用模块..."
    if ! make -C common BUILD_VERSION="$BUILD_VERSION"; then
        log_error "通用模块构建失败"
        exit 1
    fi
    
    log_info "构建104协议控制器模块..."
    if ! make -C protocol/104/controller BUILD_VERSION="$BUILD_VERSION"; then
        log_error "104协议控制器模块构建失败"
        exit 1
    fi
    
    log_info "安装控制器程序到output目录..."
    if ! make -C protocol/104/controller install; then
        log_error "控制器安装失败"
        exit 1
    fi
    
    # 打包output目录
    if [ -d "output" ]; then
        log_info "打包output目录为output.tar.gz..."
        if tar -czf output.tar.gz -C "$SCRIPT_DIR" output; then
            local tar_size=$(du -h output.tar.gz | cut -f1)
            log_info "打包完成: output.tar.gz (大小: $tar_size)"
        else
            log_error "打包失败"
            exit 1
        fi
    else
        log_warn "output目录不存在，跳过打包"
    fi
    
    log_info "所有模块构建完成"
}

# 清理构建文件
clean_build() {
    log_info "清理构建文件..."
    
    if [ -d "build" ]; then
        rm -rf build
        log_info "构建目录已清理"
    fi
    
    if [ -d "output" ]; then
        rm -rf output
        log_info "输出目录已清理"
    fi
    
    if [ -d ".build_config" ]; then
        rm -rf .build_config
        log_info "构建配置已清理"
    fi
    
    # 删除output.tar.gz
    if [ -f "output.tar.gz" ]; then
        rm -f output.tar.gz
        log_info "output.tar.gz 已删除"
    fi
    
    log_info "构建文件清理完成"
}

# 清理第三方库
clean_third_party() {
    log_info "清理第三方库..."
    
    if [ -d "third" ]; then
        rm -rf third
        log_info "第三方库目录已清理"
    fi
    
    log_info "第三方库清理完成"
}

# 显示帮助信息
show_help() {
    echo "DLSystem Protocol 构建脚本"
    echo
    echo "用法:"
    echo "  $0 set                  # 交互式配置（选择协议类型和构建版本，不自动构建）"
    echo "  $0 build                # 编译所有模块（如已配置则自动读取，否则交互式选择版本）"
    echo "  $0 build debug          # 编译debug版本（调试版本，包含所有调试信息）"
    echo "  $0 build release        # 编译release版本（生产版本，优化性能）"
    echo "  $0 clean                # 清理编译产物和输出目录"
    echo "  $0 clean all            # 清理所有内容（编译产物、第三方库）"
    echo "  $0 clone                # 克隆第三方库"
    echo "  $0 help                 # 显示帮助信息"
    echo
    echo "如果网络连接有问题，可以手动下载第三方库:"
    echo "  ./build.sh clone                         # 克隆所有第三方库"
    echo
    echo "添加新的第三方库:"
    echo "  在 config/third/ 目录下创建 <模块名>.conf 文件"
    echo "  配置文件格式:"
    echo "    github_url = https://github.com/user/repo.git"
    echo "    gitee_url = https://gitee.com/mirrors/repo.git"
    echo "    version = v1.0.0"
    echo "    check_files = file1.h,file2.c"
    echo "    include_path = src"
    echo "    source_files = file1.c,file2.c"
    echo "    libs = pthread"
    echo
}

# 主函数
main() {
    case "${1:-help}" in
        "set")
            set_config
            ;;
        "build")
            build_all "$2"
            ;;
        "clean")
            if [ "$2" = "all" ]; then
                clean_build
                clean_third_party
            else
                clean_build
            fi
            ;;
        "clone")
            clone_third_party
            ;;
        "help"|"-h"|"--help")
            show_help
            ;;
        *)
            log_error "未知命令: $1"
            show_help
            exit 1
            ;;
    esac
}

# 执行主函数
main "$@"
